#include "common.h"

sqlite3 *user_db = NULL;
char *error = NULL;
ClientNode *head = NULL;
pthread_mutex_t mutex;
#define MAX_CLIENT 128

void execute(sqlite3 *db, char *sql);
struct sockaddr_in *getAddrStruct(char *ip, short port);
void addClient(ClientNode client);
void deleteClient(int client_sock);
void removeSubstring(char *str, const char *substr);
void *responeClientRequest(void *p);

// 执行sql语句
void execute(sqlite3 *db, char *sql)
{
    int ret = sqlite3_exec(db, sql, NULL, NULL, &error);
    if (ret != SQLITE_OK)
    {
        printf("execute sql failed:%s\n", error);
    }
}
// 获取IP地址族结构体
struct sockaddr_in *getAddrStruct(char *ip, short port)
{
    // IP地址族结构体
    struct sockaddr_in *addr = malloc(sizeof(struct sockaddr_in));
    addr->sin_family = AF_INET; // IPV4网络地址

    // 把本地字节序的端口号转为网络字节序端口号
    addr->sin_port = htons(port);

    // 把字符串IP地址转为网络IP地址，并且存入指定结构体变量中
    inet_pton(AF_INET, ip, &addr->sin_addr);
    return addr;
}
// 增加客户链表节点
void addClient(ClientNode client)
{
    ClientNode *node = malloc(sizeof(ClientNode));
    node->next = NULL;
    node->user = client.user;
    node->client_sock = client.client_sock;
    node->client_addr = client.client_addr;

    ClientNode *p = head;
    while (p->next)
    {
        p = p->next;
    }
    p->next = node;
}
// 删除客户端链表节点
void deleteClient(int client_sock)
{
    if (!head->next)
    {
        return;
    }
    ClientNode *p = head;
    while (p->next)
    {
        if (p->next->client_sock == client_sock)
        {
            ClientNode *q = p->next;
            p->next = q->next;
            free(q);
            break;
        }
        p = p->next;
    }
}
// 删除字符串中的指定子串（往前多删除了一位用于去掉间隔符）
void removeSubstring(char *str, const char *substr)
{
    size_t str_len = strlen(str);
    size_t substr_len = strlen(substr);

    if (substr_len == 0 || str_len < substr_len)
    {
        return;
    }              // 如果子串为空或原串比子串短，则不进行操作
    char *p = str; // 指向当前正在检查的位置
    char *found;   // 记录找到子串的位置

    while (found = strstr(p, substr))
    {                                                                                     // 使用strstr查找子串
        memmove(found - 1, found + substr_len, str_len - (found - str - substr_len) + 1); // 删除找到的子串，使用memmove避免覆盖
        str_len -= substr_len;                                                            // 更新剩余字符串长度
        p = found;                                                                        // 更新搜索起点到刚刚修改过的地方
    }
}
/* 响应客户端消息
**这个函数负责处理客户端发送的消息，根据消息类型执行相应的操作，
**如用户注册、登录、单点聊天、群组聊天等，并将处理结果返回给客户端。
**p 指向ClientNode结构体的指针，包含客户端的连接信息和用户数据。
*/
void *responeClientRequest(void *p)
{
    char buf[30];
    ClientNode client = *(ClientNode *)p;
    // 客户端连接上线通知
    short port = ntohs(client.client_addr.sin_port);
    inet_ntop(AF_INET, &client.client_addr.sin_addr, buf, sizeof(buf));
    printf("客户端[%s:%d]已上线\n", buf, port);
    // 主循环,不断读取客户端消息并处理
    while (1)
    {
        Message msg;
        char sql[128] = "SELECT * FROM user";
        int row = 0, column = 0; // 行列变量用于SQL存储查询结果的维度
        char **result = NULL;    // 用于存储SQL查询结果
        User rev_user;
        // 尝试读取客户端的消息,连接断开则退出循环(已验证)
        if (read(client.client_sock, &msg, sizeof(msg)) <= 0)
        {
            printf("客户端[%s:%d]断开连接\n", buf, port);
            pthread_mutex_lock(&mutex);
            deleteClient(client.client_sock);
            pthread_mutex_unlock(&mutex);
            close(client.client_sock);
            break;
        }
        // 注册处理(已验证)
        if (msg.type == REGISTER)
        {
            rev_user = msg.msg_from;
            sqlite3_get_table(user_db, sql, &result, &row, &column, &error);
            for (int i = 1; i <= row; i++)
            {
                if (!strcmp(msg.msg_from.name, result[i * column]))
                {
                    strcpy(msg.content, "NO");
                    write(client.client_sock, &msg, sizeof(msg));
                    break;
                }
            }
            if (strcmp(msg.content, "NO"))
            {
                sprintf(sql, "INSERT INTO user VALUES('%s','%s','%s','%s','')",
                        rev_user.name, rev_user.password, rev_user.question, rev_user.answer);
                pthread_mutex_lock(&mutex);
                execute(user_db, sql);
                pthread_mutex_unlock(&mutex);
                strcpy(msg.content, "OK");
            }
            write(client.client_sock, &msg, sizeof(msg));
        }
        // 登录处理(已验证)
        else if (msg.type == LOGIN)
        {
            int flag = 1;
            sqlite3_get_table(user_db, sql, &result, &row, &column, &error);
            ClientNode *p = head;
            while (p->next)
            {
                p = p->next;
                if (!strcmp(p->user.name, msg.msg_from.name))
                {
                    flag = 0;
                    strcpy(msg.content, "REPET");
                    write(client.client_sock, &msg, sizeof(msg));
                    break;
                }
            }
            if (flag)
            {
                for (int i = 1; i <= row; i++)
                {
                    if (!strcmp(msg.msg_from.name, result[i * column]) &&
                        !strcmp(msg.msg_from.password, result[i * column + 1]))
                    {
                        strcpy(msg.content, "YES");
                        write(client.client_sock, &msg, sizeof(msg));
                        client.user = msg.msg_from;
                        pthread_mutex_lock(&mutex);
                        addClient(client);
                        pthread_mutex_unlock(&mutex);
                        break;
                    }
                }
                if (strcmp(msg.content, "YES"))
                {
                    strcpy(msg.content, "NO");
                    write(client.client_sock, &msg, sizeof(msg));
                }
            }
        }
        // 找回密码处理(已验证)
        else if (msg.type == FIND_PASSWORD)
        {
            int flag = 1;
            rev_user = msg.msg_from;
            int ret = sqlite3_get_table(user_db, sql, &result, &row, &column, &error);
            for (int i = 1; i <= row; i++)
            {
                // 判断用户名是否正确
                if (strcmp(result[i * column], rev_user.name) == 0)
                {
                    flag = 0;
                    sprintf(msg.content, "密保问题:%s\n请输入你的密保答案:", result[i * column + 2]);
                    write(client.client_sock, &msg, sizeof(msg));
                    // 判断用户密保答案是否正确
                    read(client.client_sock, &msg, sizeof(msg));
                    if (strcmp(msg.msg_from.answer, result[i * column + 3]) == 0)
                    {
                        write(client.client_sock, &msg, sizeof(msg));
                        // 接收用户输入的新密码
                        read(client.client_sock, &msg, sizeof(msg));
                        // 更新用户数据库密码
                        sprintf(sql, "UPDATE user SET password='%s' WHERE name='%s';",
                                msg.msg_from.password, msg.msg_from.name);
                        pthread_mutex_lock(&mutex);
                        execute(user_db, sql);
                        pthread_mutex_unlock(&mutex);
                        // 返回修改密码成功
                        strcpy(msg.content, "密码修改成功");
                        write(client.client_sock, &msg, sizeof(msg));
                        break;
                    }
                    else
                    {
                        strcpy(msg.content, "密保答案错误");
                        write(client.client_sock, &msg, sizeof(msg));
                    }
                }
            }
            if (flag)
            {
                strcpy(msg.content, "未找到该用户");
                write(client.client_sock, &msg, sizeof(msg));
            }
        }
        // 单聊对象判断(已验证)
        else if (msg.type == PRIVATE)
        {
            sqlite3_get_table(user_db, sql, &result, &row, &column, &error);
            for (int i = 1; i <= row; i++)
            {
                if (strcmp(result[i * column], msg.msg_from.name) == 0)
                {
                    if (strstr(result[i * column + 4], msg.msg_to.name))
                    {
                        strcpy(msg.content, "YES");
                    }
                    else
                    {
                        strcpy(msg.content, "NO");
                    }
                    write(client.client_sock, &msg, sizeof(msg));
                    break;
                }
            }
        }
        // 单聊消息转发和聊天记录保存(已验证)
        else if (msg.type == PRIVATE_CHAT)
        {
            time_t time_now = time(NULL);
            strftime(msg.time, sizeof(msg.time), "%Y-%m-%d %H:%M:%S", localtime(&time_now));
            ClientNode *p = head;
            while (p->next)
            {
                p = p->next;
                if (strcmp(p->user.name, msg.msg_to.name) == 0)
                {
                    write(p->client_sock, &msg, sizeof(msg));
                }
            }
            sprintf(sql, "INSERT INTO reconds VALUES('%s','%s','%s','%s');",
                    msg.msg_from.name, msg.msg_to.name, msg.content, msg.time);
            pthread_mutex_lock(&mutex);
            execute(user_db, sql);
            pthread_mutex_unlock(&mutex);
        }
        // 群聊消息转发和聊天记录保存(已验证)
        else if (msg.type == GROUP)
        {
            time_t time_now = time(NULL);
            strftime(msg.time, sizeof(msg.time), "%Y-%m-%d %H:%M:%S", localtime(&time_now));
            sqlite3_get_table(user_db, sql, &result, &row, &column, &error);
            ClientNode *p = head;
            while (p->next)
            {
                p = p->next;
                for (int i = 1; i <= row; i++)
                {
                    if (!strcmp(result[i * column], msg.msg_from.name) && strstr(result[i * column + 4], p->user.name))
                    {
                        write(p->client_sock, &msg, sizeof(msg));
                        sprintf(sql, "INSERT INTO reconds VALUES('%s','%s','%s','%s');",
                                msg.msg_from.name, p->user.name, msg.content, msg.time);
                        pthread_mutex_lock(&mutex);
                        execute(user_db, sql);
                        pthread_mutex_unlock(&mutex);
                    }
                }
            }
        }
        // 添加好友(已验证)
        else if (msg.type == ADD_FRIEND)
        {
            int flag_1 = 1, flag_2, flag_3;
            char friends[900];
            sqlite3_get_table(user_db, sql, &result, &row, &column, &error);
            if (strcmp(msg.msg_from.name, msg.msg_to.name) == 0)
            {
                strcpy(msg.content, "ME");
                write(client.client_sock, &msg, sizeof(msg));
                continue;
            }
            for (int i = 1; i <= row; i++)
            {
                if (strcmp(result[i * column], msg.msg_to.name) == 0)
                {
                    flag_1 = 0;
                }
            }
            if (flag_1)
            {
                strcpy(msg.content, "NO");
                write(client.client_sock, &msg, sizeof(msg));
                continue;
            }
            for (int i = 1; i <= row; i++)
            {
                if (strcmp(result[i * column], msg.msg_from.name) == 0)
                {
                    memset(friends, 0, sizeof(friends));
                    memcpy(friends, result[i * column + 4], sizeof(result[i * column + 4]));
                    sprintf(friends, "%s$%s", friends, msg.msg_to.name);
                    sprintf(sql, "UPDATE user SET friends='%s' WHERE name='%s';",
                            friends, msg.msg_from.name);
                    pthread_mutex_lock(&mutex);
                    execute(user_db, sql);
                    pthread_mutex_unlock(&mutex);
                    flag_2 = 1;
                }
                if (strcmp(result[i * column], msg.msg_to.name) == 0)
                {
                    memset(friends, 0, sizeof(friends));
                    memcpy(friends, result[i * column + 4], sizeof(result[i * column + 4]));
                    sprintf(friends, "%s$%s", friends, msg.msg_from.name);
                    sprintf(sql, "UPDATE user SET friends='%s' WHERE name='%s';",
                            friends, msg.msg_to.name);
                    pthread_mutex_lock(&mutex);
                    execute(user_db, sql);
                    pthread_mutex_unlock(&mutex);
                    flag_3 = 1;
                }
            }
            if (flag_2 && flag_3)
            {
                strcpy(msg.content, "YES");
                write(client.client_sock, &msg, sizeof(msg));
            }
        }
        // 删除好友(已验证)
        else if (msg.type == DELETE_FRIEND)
        {
            int flag_1, flag_2;
            char friends[900];
            sqlite3_get_table(user_db, sql, &result, &row, &column, &error);
            for (int i = 1; i <= row; i++)
            {
                if (strcmp(result[i * column], msg.msg_from.name) == 0)
                {
                    if (!strstr(result[i * column + 4], msg.msg_to.name))
                    {
                        strcpy(msg.content, "NO");
                        write(client.client_sock, &msg, sizeof(msg));
                        break;
                    }
                    memset(friends, 0, sizeof(friends));
                    memcpy(friends, result[i * column + 4], sizeof(result[i * column + 4]));
                    removeSubstring(friends, msg.msg_to.name); // 删除字符串中的指定子串（往前多删除了一位用于去掉间隔符）
                    sprintf(sql, "UPDATE user SET friends='%s' WHERE name='%s';",
                            friends, msg.msg_from.name);
                    pthread_mutex_lock(&mutex);
                    execute(user_db, sql);
                    pthread_mutex_unlock(&mutex);
                    flag_1 = 1;
                }
                if (strcmp(result[i * column], msg.msg_to.name) == 0)
                {
                    memset(friends, 0, sizeof(friends));
                    memcpy(friends, result[i * column + 4], sizeof(result[i * column + 4]));
                    removeSubstring(friends, msg.msg_from.name); // 删除字符串中的指定子串（往前多删除了一位用于去掉间隔符）
                    sprintf(sql, "UPDATE user SET friends='%s' WHERE name='%s';",
                            friends, msg.msg_to.name);
                    pthread_mutex_lock(&mutex);
                    execute(user_db, sql);
                    pthread_mutex_unlock(&mutex);
                    flag_2 = 1;
                }
            }
            if (flag_1 && flag_2)
            {
                strcpy(msg.content, "YES");
                write(client.client_sock, &msg, sizeof(msg));
            }
        }
        // 聊天记录展示(已验证)
        else if (msg.type == SHOW_RECONDS)
        {
            strcpy(sql, "SELECT * FROM reconds");
            sqlite3_get_table(user_db, sql, &result, &row, &column, &error);
            for (int i = 1; i <= row; i++)
            {
                if (!strcmp(result[i * column], msg.msg_from.name) || !strcmp(result[i * column + 1], msg.msg_from.name))
                {
                    sprintf(msg.time, "%s", result[i * column + 3]);
                    sprintf(msg.msg_to.name, "%s", result[i * column]);
                    sprintf(msg.content, "%s", result[i * column + 2]);
                    // sprintf(msg.content, "%s\n%s: %s", result[i * column + 3], result[i * column], result[i * column + 2]);
                    write(client.client_sock, &msg, sizeof(msg));
                }
            }
            strcpy(msg.content, "END");
            write(client.client_sock, &msg, sizeof(msg));
        }
        // 文件上传(已验证)
        else if (msg.type == SEND_FILE)
        {
            File *file;
            pthread_mutex_lock(&mutex);
            int fd = open("server_recv.c", O_WRONLY | O_CREAT | O_TRUNC, 0666);
            while (1)
            {
                read(client.client_sock, &msg, sizeof(msg));
                if (msg.type == FILE_END)
                {
                    break;
                }
                file = (File *)msg.content;
                write(fd, file->buf, file->send_byte);
            }
            pthread_mutex_unlock(&mutex);
        }
        // 可下载文件展示
        else if (msg.type == SHOW_FILE)
        {
            int num = 0;
            DIR *directory = opendir("./");
            struct dirent *dir = readdir(directory);
            while (dir)
            {
                if (strcmp(dir->d_name, ".") && strcmp(dir->d_name, ".."))
                {
                    if (num == 0)
                    {
                        memcpy(msg.content, dir->d_name, sizeof(dir->d_name));
                    }
                    else
                    {
                        sprintf(msg.content, "%s\n%s", msg.content, dir->d_name);
                    }
                }
                dir = readdir(directory);
                num++;
            }
            write(client.client_sock, &msg, sizeof(msg));
            closedir(directory);
        }
        // 文件下载
        else if (msg.type == RECV_FILE)
        {
            File file;
            struct stat st;
            int complete_bytes; // 文件已发送的字节数
            int send_bytes;     // 文件本次发送的字节数
            int fd = open(msg.msg_to.name, O_RDONLY);

            stat(msg.msg_to.name, &st);
            
            pthread_mutex_lock(&mutex);
            while (1)
            {
                send_bytes = st.st_size - complete_bytes;
                if (send_bytes == 0)
                {
                    break;
                }
                // printf("已发送%d字节\n", complete_bytes);
                send_bytes = send_bytes > 1000 ? 1000 : send_bytes;
                complete_bytes += send_bytes;

                file.file_byte = st.st_size;
                file.send_byte = send_bytes;
                read(fd, file.buf, send_bytes);
                memcpy(msg.content, &file, sizeof(file));

                write(client.client_sock, &msg, sizeof(msg));
            }
            msg.type = FILE_END;
            write(client.client_sock, &msg, sizeof(msg));
            pthread_mutex_unlock(&mutex);
        }
        // 退出登陆处理
        else if (msg.type == EXIT)
        {
            pthread_mutex_lock(&mutex);
            deleteClient(client.client_sock);
            pthread_mutex_unlock(&mutex);
        }
        // printf("-----msg.type == %d\n",msg.type);
    }
}
// 主函数：创建服务器，监听客户端连接，并处理客户端请求。
int main(int argc, char const *argv[])
{
    int opt = 1;
    pthread_mutex_init(&mutex, NULL);
    head = malloc(sizeof(ClientNode)); // 初始化客户端链表
    head->next = NULL;

    sqlite3_open("user.db", &user_db);
    // 创建服务器地址结构体
    struct sockaddr *server_addr = (struct sockaddr *)getAddrStruct("192.168.30.27", 9000);
    int server_sock = socket(AF_INET, SOCK_STREAM, 0);
    // 打开地址重复绑定的功能
    setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    // 将套接字绑定到指定地址
    if (-1 == bind(server_sock, server_addr, sizeof(struct sockaddr)))
    {
        perror("绑定地址出错\n");
    }
    // 监听套接字，等待客户端连接
    listen(server_sock, MAX_CLIENT);
    while (1)
    {
        pthread_t p_id;
        struct sockaddr_in client_addr;
        int sz = sizeof(client_addr);

        // 接受客户端连接
        int client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &sz);
        if (client_sock == -1)
        {
            perror("接受客户端连接失败\n");
            continue;
        }
        ClientNode client = {.client_sock = client_sock, .client_addr = client_addr};
        pthread_create(&p_id, NULL, responeClientRequest, &client);
    }
    close(server_sock);
    sqlite3_close(user_db);
    free(server_addr);
    free(head);
    return 0;
}
